/*
 * Copyright 2018- The Pixie Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "src/stirling/source_connectors/socket_tracer/protocols/tls/parse.h"

#include "src/common/testing/testing.h"

namespace px {
namespace stirling {
namespace protocols {

using ::testing::Contains;

// clang-format off

constexpr uint8_t kChangeCipherSpec[] = {
  0x14, 0x03, 0x03, 0x00, 0x01, 0x01,
};

constexpr uint8_t kApplicationData[] = {
  0x17, 0x03, 0x03, 0x00, 0x29, 0xec, 0x19, 0x69, 0x2d, 0x60, 0x95, 0x55, 0xaa, 0x49, 0xac, 0xa6,
  0x93, 0x2f, 0x3f, 0x63, 0xfa, 0x9a, 0x6f, 0x09, 0xe7, 0x9f, 0xf5, 0x1f, 0xbb, 0x12, 0x68, 0x47,
  0x4c, 0x8d, 0x03, 0x1d, 0x97, 0xba, 0x97, 0x6d, 0xdc, 0x81, 0xa4, 0x25, 0x83, 0x56
};

constexpr uint8_t kClientHelloNeedsMoreData[] = {
  0x16, 0x03, 0x01, 0x01, 0x1a, 0x01, 0x00, 0x01, 0x16, 0x03, 0x03, 0x5f, 0xca, 0xbd, 0x4b, 0x62,
  0x28, 0x15, 0x8f, 0x91, 0x74, 0xdf, 0x43, 0xa2, 0x2c, 0xa6, 0x2d, 0xe7, 0x3b, 0x5b, 0x34, 0x91,
};

constexpr uint8_t kInvalidSessionID[] = {
  0x16, 0x03, 0x01, 0x01, 0x1a, 0x01, 0x00, 0x01, 0x16, 0x03, 0x03, 0x5f, 0xca, 0xbd, 0x4b, 0x62,
  0x28, 0x15, 0x8f, 0x91, 0x74, 0xdf, 0x43, 0xa2, 0x2c, 0xa6, 0x2d, 0xe7, 0x3b, 0x5b, 0x34, 0x91,
  // 11th byte must be between 0 and 32
  0xe0, 0x55, 0x1d, 0xc9, 0x26, 0xc5, 0xa4, 0x29, 0xad, 0x36, 0xe5, 0xff, 0x0b, 0x19, 0xc5, 0xa5,
  0xa1, 0x6c, 0xfa, 0x2e, 0x64, 0x42, 0x6f, 0xed, 0xe0, 0x06, 0xef, 0x08, 0x2f, 0x71, 0x58, 0x8b,
  0x25, 0x5c, 0xf0, 0x5d, 0xbf, 0x16, 0x2a, 0xa2, 0x52, 0x0b, 0xc2, 0xfe, 0x00, 0x26, 0xc0, 0x2b,
  0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x0a,
  0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0xc0, 0x12, 0x00, 0x0a, 0x13, 0x01,
  0x13, 0x02, 0x13, 0x03, 0x01, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x00,
  0x1a, 0x61, 0x72, 0x67, 0x6f, 0x63, 0x64, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d,
  0x72, 0x65, 0x70, 0x6f, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x05, 0x00, 0x05, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
  0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x18, 0x08, 0x04,
  0x04, 0x03, 0x08, 0x07, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x05, 0x03,
  0x06, 0x03, 0x02, 0x01, 0x02, 0x03, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
  0x10, 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x05,
  0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xf4,
  0x82, 0x10, 0xb1, 0x65, 0x1a, 0xf3, 0x04, 0x82, 0xbb, 0x82, 0x83, 0x85, 0xbc, 0xc5, 0x01, 0x62,
  0xe4, 0x15, 0x84, 0x8f, 0x7b, 0x12, 0x37, 0xf1, 0xaf, 0x7b, 0x1f, 0xfd, 0xf0, 0xf5, 0x1b,
};

constexpr uint8_t kInvalidContentType[] = {
  // First byte must be one of tls::ContentType.
  0x19, 0x03, 0x01, 0x01, 0x1a, 0x01, 0x00, 0x01, 0x16, 0x03, 0x03, 0x5f, 0xca, 0xbd, 0x4b, 0x62,
  0x28, 0x15, 0x8f, 0x91, 0x74, 0xdf, 0x43, 0xa2, 0x2c, 0xa6, 0x2d, 0xe7, 0x3b, 0x5b, 0x34, 0x91,
  0xe0, 0x55, 0x1d, 0xc9, 0x26, 0xc5, 0xa4, 0x29, 0xad, 0x36, 0xe5, 0x20, 0x0b, 0x19, 0xc5, 0xa5,
  0xa1, 0x6c, 0xfa, 0x2e, 0x64, 0x42, 0x6f, 0xed, 0xe0, 0x06, 0xef, 0x08, 0x2f, 0x71, 0x58, 0x8b,
  0x25, 0x5c, 0xf0, 0x5d, 0xbf, 0x16, 0x2a, 0xa2, 0x52, 0x0b, 0xc2, 0xfe, 0x00, 0x26, 0xc0, 0x2b,
  0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x0a,
  0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0xc0, 0x12, 0x00, 0x0a, 0x13, 0x01,
  0x13, 0x02, 0x13, 0x03, 0x01, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x00,
  0x1a, 0x61, 0x72, 0x67, 0x6f, 0x63, 0x64, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d,
  0x72, 0x65, 0x70, 0x6f, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x05, 0x00, 0x05, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
  0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x18, 0x08, 0x04,
  0x04, 0x03, 0x08, 0x07, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x05, 0x03,
  0x06, 0x03, 0x02, 0x01, 0x02, 0x03, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
  0x10, 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x05,
  0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xf4,
  0x82, 0x10, 0xb1, 0x65, 0x1a, 0xf3, 0x04, 0x82, 0xbb, 0x82, 0x83, 0x85, 0xbc, 0xc5, 0x01, 0x62,
  0xe4, 0x15, 0x84, 0x8f, 0x7b, 0x12, 0x37, 0xf1, 0xaf, 0x7b, 0x1f, 0xfd, 0xf0, 0xf5, 0x1b,
};

constexpr uint8_t kInvalidLegacyVersion[] = {
  // Second and third bytes are invalid legacy version (should be between 0x0300 and 0x0304).
  0x16, 0x02, 0x01, 0x01, 0x1a, 0x01, 0x00, 0x01, 0x16, 0x03, 0x03, 0x5f, 0xca, 0xbd, 0x4b, 0x62,
  0x28, 0x15, 0x8f, 0x91, 0x74, 0xdf, 0x43, 0xa2, 0x2c, 0xa6, 0x2d, 0xe7, 0x3b, 0x5b, 0x34, 0x91,
  0xe0, 0x55, 0x1d, 0xc9, 0x26, 0xc5, 0xa4, 0x29, 0xad, 0x36, 0xe5, 0x20, 0x0b, 0x19, 0xc5, 0xa5,
  0xa1, 0x6c, 0xfa, 0x2e, 0x64, 0x42, 0x6f, 0xed, 0xe0, 0x06, 0xef, 0x08, 0x2f, 0x71, 0x58, 0x8b,
  0x25, 0x5c, 0xf0, 0x5d, 0xbf, 0x16, 0x2a, 0xa2, 0x52, 0x0b, 0xc2, 0xfe, 0x00, 0x26, 0xc0, 0x2b,
  0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x0a,
  0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0xc0, 0x12, 0x00, 0x0a, 0x13, 0x01,
  0x13, 0x02, 0x13, 0x03, 0x01, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x00,
  0x1a, 0x61, 0x72, 0x67, 0x6f, 0x63, 0x64, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d,
  0x72, 0x65, 0x70, 0x6f, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x05, 0x00, 0x05, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
  0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x18, 0x08, 0x04,
  0x04, 0x03, 0x08, 0x07, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x05, 0x03,
  0x06, 0x03, 0x02, 0x01, 0x02, 0x03, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
  0x10, 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x05,
  0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xf4,
  0x82, 0x10, 0xb1, 0x65, 0x1a, 0xf3, 0x04, 0x82, 0xbb, 0x82, 0x83, 0x85, 0xbc, 0xc5, 0x01, 0x62,
  0xe4, 0x15, 0x84, 0x8f, 0x7b, 0x12, 0x37, 0xf1, 0xaf, 0x7b, 0x1f, 0xfd, 0xf0, 0xf5, 0x1b,
};

constexpr uint8_t kInvalidHandshakeType[] = {
  // Sixth byte must be one of tls::HandshakeType.
  0x16, 0x03, 0x01, 0x01, 0x1a, 0x19, 0x00, 0x01, 0x16, 0x03, 0x03, 0x5f, 0xca, 0xbd, 0x4b, 0x62,
  0x28, 0x15, 0x8f, 0x91, 0x74, 0xdf, 0x43, 0xa2, 0x2c, 0xa6, 0x2d, 0xe7, 0x3b, 0x5b, 0x34, 0x91,
  0xe0, 0x55, 0x1d, 0xc9, 0x26, 0xc5, 0xa4, 0x29, 0xad, 0x36, 0xe5, 0x20, 0x0b, 0x19, 0xc5, 0xa5,
  0xa1, 0x6c, 0xfa, 0x2e, 0x64, 0x42, 0x6f, 0xed, 0xe0, 0x06, 0xef, 0x08, 0x2f, 0x71, 0x58, 0x8b,
  0x25, 0x5c, 0xf0, 0x5d, 0xbf, 0x16, 0x2a, 0xa2, 0x52, 0x0b, 0xc2, 0xfe, 0x00, 0x26, 0xc0, 0x2b,
  0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x0a,
  0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0xc0, 0x12, 0x00, 0x0a, 0x13, 0x01,
  0x13, 0x02, 0x13, 0x03, 0x01, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x00,
  0x1a, 0x61, 0x72, 0x67, 0x6f, 0x63, 0x64, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d,
  0x72, 0x65, 0x70, 0x6f, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x05, 0x00, 0x05, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
  0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x18, 0x08, 0x04,
  0x04, 0x03, 0x08, 0x07, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x05, 0x03,
  0x06, 0x03, 0x02, 0x01, 0x02, 0x03, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
  0x10, 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x05,
  0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xf4,
  0x82, 0x10, 0xb1, 0x65, 0x1a, 0xf3, 0x04, 0x82, 0xbb, 0x82, 0x83, 0x85, 0xbc, 0xc5, 0x01, 0x62,
  0xe4, 0x15, 0x84, 0x8f, 0x7b, 0x12, 0x37, 0xf1, 0xaf, 0x7b, 0x1f, 0xfd, 0xf0, 0xf5, 0x1b,
};

constexpr uint8_t kInvalidHandshakeVersion[] = {
  // 10th and 11th bytes must be between 0x0300 and 0x0304.
  0x16, 0x03, 0x01, 0x01, 0x1a, 0x01, 0x00, 0x01, 0x16, 0x02, 0x03, 0x5f, 0xca, 0xbd, 0x4b, 0x62,
  0x28, 0x15, 0x8f, 0x91, 0x74, 0xdf, 0x43, 0xa2, 0x2c, 0xa6, 0x2d, 0xe7, 0x3b, 0x5b, 0x34, 0x91,
  0xe0, 0x55, 0x1d, 0xc9, 0x26, 0xc5, 0xa4, 0x29, 0xad, 0x36, 0xe5, 0x20, 0x0b, 0x19, 0xc5, 0xa5,
  0xa1, 0x6c, 0xfa, 0x2e, 0x64, 0x42, 0x6f, 0xed, 0xe0, 0x06, 0xef, 0x08, 0x2f, 0x71, 0x58, 0x8b,
  0x25, 0x5c, 0xf0, 0x5d, 0xbf, 0x16, 0x2a, 0xa2, 0x52, 0x0b, 0xc2, 0xfe, 0x00, 0x26, 0xc0, 0x2b,
  0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x0a,
  0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0xc0, 0x12, 0x00, 0x0a, 0x13, 0x01,
  0x13, 0x02, 0x13, 0x03, 0x01, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x00,
  0x1a, 0x61, 0x72, 0x67, 0x6f, 0x63, 0x64, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d,
  0x72, 0x65, 0x70, 0x6f, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x05, 0x00, 0x05, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
  0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x18, 0x08, 0x04,
  0x04, 0x03, 0x08, 0x07, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x05, 0x03,
  0x06, 0x03, 0x02, 0x01, 0x02, 0x03, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
  0x10, 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x05,
  0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xf4,
  0x82, 0x10, 0xb1, 0x65, 0x1a, 0xf3, 0x04, 0x82, 0xbb, 0x82, 0x83, 0x85, 0xbc, 0xc5, 0x01, 0x62,
  0xe4, 0x15, 0x84, 0x8f, 0x7b, 0x12, 0x37, 0xf1, 0xaf, 0x7b, 0x1f, 0xfd, 0xf0, 0xf5, 0x1b,
};

// This exposed a bug with parsing the TLS record length
constexpr uint8_t kFailedTLSv1_2[] = {
  0x16, 0x03, 0x01, 0x00, 0xCB, 0x01, 0x00, 0x00, 0xC7, 0x03, 0x03, 0x7F, 0xC7, 0x41, 0xBC, 0xDE,
  0xF7, 0x3F, 0x09, 0x3A, 0xCB, 0x00, 0x91, 0x38, 0x72, 0xE7, 0x74, 0x81, 0xDE, 0x8D, 0xDD, 0x9F,
  0x0F, 0xA7, 0x0D, 0x29, 0xC0, 0x43, 0x7A, 0xD2, 0x4C, 0x4B, 0xBF, 0x00, 0x00, 0x38, 0xC0, 0x2C,
  0xC0, 0x30, 0x00, 0x9F, 0xCC, 0xA9, 0xCC, 0xA8, 0xCC, 0xAA, 0xC0, 0x2B, 0xC0, 0x2F, 0x00, 0x9E,
  0xC0, 0x24, 0xC0, 0x28, 0x00, 0x6B, 0xC0, 0x23, 0xC0, 0x27, 0x00, 0x67, 0xC0, 0x0A, 0xC0, 0x14,
  0x00, 0x39, 0xC0, 0x09, 0xC0, 0x13, 0x00, 0x33, 0x00, 0x9D, 0x00, 0x9C, 0x00, 0x3D, 0x00, 0x3C,
  0x00, 0x35, 0x00, 0x2F, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x66, 0x00, 0x0B, 0x00, 0x04, 0x03, 0x00,
  0x01, 0x02, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x1D, 0x00, 0x17, 0x00, 0x1E, 0x00, 0x19,
  0x00, 0x18, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x0C, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70,
  0x2F, 0x31, 0x2E, 0x31, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x30,
  0x00, 0x2E, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x07, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0A,
  0x08, 0x0B, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x03, 0x03,
  0x02, 0x03, 0x03, 0x01, 0x02, 0x01, 0x03, 0x02, 0x02, 0x02, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02,
};

// This caught a bug where TLS extensions can have a length of 0. Prior to this we unconditionally
// tried to parse a server_name extension that had a length of 0.
constexpr uint8_t kServerHelloWithZeroLengthExtension[] = {
  0x16, 0x03, 0x03, 0x00, 0x70, 0x02, 0x00, 0x00, 0x6C, 0x03, 0x03, 0xBD, 0x83, 0x64, 0x96, 0xD6,
  0xFF, 0x59, 0x80, 0x83, 0x9C, 0x52, 0x71, 0x47, 0x7A, 0xCF, 0x8A, 0xA8, 0xAF, 0x6C, 0xC6, 0xD1,
  0x67, 0x84, 0xDA, 0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x01, 0x20, 0xC3, 0x59, 0x22, 0x59,
  0x51, 0x13, 0x7E, 0x7C, 0x4C, 0xD0, 0xD3, 0xCD, 0x54, 0x10, 0x54, 0xB1, 0xF4, 0xCE, 0x27, 0x3E,
  0x50, 0xAD, 0x67, 0x04, 0xEF, 0x1D, 0x07, 0x50, 0x22, 0x82, 0x21, 0xBF, 0xC0, 0x30, 0x00, 0x00,
  0x24, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x04, 0x03, 0x00,
  0x01, 0x02, 0x00, 0x10, 0x00, 0x0B, 0x00, 0x09, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2F, 0x31, 0x2E,
  0x31, 0x00, 0x17, 0x00, 0x00,
};

constexpr uint8_t kValidClientHello[] = {
  0x16, 0x03, 0x01, 0x01, 0x1a, 0x01, 0x00, 0x01, 0x16, 0x03, 0x03, 0x5f, 0xca, 0xbd, 0x4b, 0x62,
  0x28, 0x15, 0x8f, 0x91, 0x74, 0xdf, 0x43, 0xa2, 0x2c, 0xa6, 0x2d, 0xe7, 0x3b, 0x5b, 0x34, 0x91,
  0xe0, 0x55, 0x1d, 0xc9, 0x26, 0xc5, 0xa4, 0x29, 0xad, 0x36, 0xe5, 0x20, 0x0b, 0x19, 0xc5, 0xa5,
  0xa1, 0x6c, 0xfa, 0x2e, 0x64, 0x42, 0x6f, 0xed, 0xe0, 0x06, 0xef, 0x08, 0x2f, 0x71, 0x58, 0x8b,
  0x25, 0x5c, 0xf0, 0x5d, 0xbf, 0x16, 0x2a, 0xa2, 0x52, 0x0b, 0xc2, 0xfe, 0x00, 0x26, 0xc0, 0x2b,
  0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x0a,
  0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0xc0, 0x12, 0x00, 0x0a, 0x13, 0x01,
  0x13, 0x02, 0x13, 0x03, 0x01, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x00,
  0x1a, 0x61, 0x72, 0x67, 0x6f, 0x63, 0x64, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d,
  0x72, 0x65, 0x70, 0x6f, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x05, 0x00, 0x05, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
  0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x18, 0x08, 0x04,
  0x04, 0x03, 0x08, 0x07, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x05, 0x03,
  0x06, 0x03, 0x02, 0x01, 0x02, 0x03, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
  0x10, 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x05,
  0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xf4,
  0x82, 0x10, 0xb1, 0x65, 0x1a, 0xf3, 0x04, 0x82, 0xbb, 0x82, 0x83, 0x85, 0xbc, 0xc5, 0x01, 0x62,
  0xe4, 0x15, 0x84, 0x8f, 0x7b, 0x12, 0x37, 0xf1, 0xaf, 0x7b, 0x1f, 0xfd, 0xf0, 0xf5, 0x1b,
};

constexpr uint8_t kServerHello[] = {
  0x16, 0x03, 0x03, 0x00, 0x7a, 0x02, 0x00, 0x00, 0x76, 0x03, 0x03, 0x66, 0x13, 0xca, 0x43, 0x26,
  0x96, 0x9a, 0xf6, 0x10, 0x0f, 0x5d, 0x1a, 0x3e, 0x59, 0x54, 0xd6, 0x45, 0x52, 0xe1, 0x07, 0xba,
  0x60, 0x67, 0x2f, 0x97, 0x5f, 0x27, 0x6b, 0xfc, 0x37, 0x5d, 0xaf, 0x20, 0x0b, 0x19, 0xc5, 0xa5,
  0xa1, 0x6c, 0xfa, 0x2e, 0x64, 0x42, 0x6f, 0xed, 0xe0, 0x06, 0xef, 0x08, 0x2f, 0x71, 0x58, 0x8b,
  0x25, 0x5c, 0xf0, 0x5d, 0xbf, 0x16, 0x2a, 0xa2, 0x52, 0x0b, 0xc2, 0xfe, 0x13, 0x01, 0x00, 0x00,
  0x2e, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04, 0x00, 0x33, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x28,
  0xc5, 0x43, 0x52, 0x4f, 0x61, 0xf4, 0x7a, 0x2b, 0xc5, 0xcc, 0x43, 0x27, 0x0e, 0xe8, 0xa0, 0xc2,
  0x6e, 0x2a, 0x86, 0x60, 0x80, 0x96, 0x5d, 0xdf, 0xfb, 0x86, 0xe2, 0x46, 0xe9, 0x6e, 0x5c,
};

// clang-format on

class TLSParserTest : public ::testing::Test {};

TEST_F(TLSParserTest, ParseValidChangeCipherSpec) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kChangeCipherSpec));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);

  ASSERT_EQ(frame.content_type, tls::ContentType::kChangeCipherSpec);
  ASSERT_EQ(frame.length, 0x1);
  ASSERT_EQ(frame.legacy_version, tls::LegacyVersion::kTLS1_2);
  ASSERT_EQ(state, ParseState::kSuccess);
}

TEST_F(TLSParserTest, ParseValidApplicationData) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kApplicationData));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);

  ASSERT_EQ(frame.content_type, tls::ContentType::kApplicationData);
  ASSERT_EQ(frame.legacy_version, tls::LegacyVersion::kTLS1_2);
  ASSERT_EQ(frame.length, 41);
  ASSERT_EQ(state, ParseState::kSuccess);
}

TEST_F(TLSParserTest, NeedsMoreData) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kClientHelloNeedsMoreData));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);
  ASSERT_EQ(state, ParseState::kNeedsMoreData);
}

TEST_F(TLSParserTest, TLSv1_2_InvalidTLSRecordLengthBug) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kFailedTLSv1_2));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);
  ASSERT_EQ(state, ParseState::kSuccess);
}

TEST_F(TLSParserTest, InvalidContentType) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kInvalidContentType));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);
  ASSERT_EQ(state, ParseState::kInvalid);
}

TEST_F(TLSParserTest, InvalidLegacyVersion) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kInvalidLegacyVersion));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);
  ASSERT_EQ(state, ParseState::kInvalid);
}

TEST_F(TLSParserTest, InvalidHandshakeType) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kInvalidHandshakeType));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);
  ASSERT_EQ(state, ParseState::kInvalid);
}

TEST_F(TLSParserTest, InvalidHandshakeVersion) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kInvalidHandshakeVersion));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);
  ASSERT_EQ(state, ParseState::kInvalid);
}

TEST_F(TLSParserTest, InvalidSessionID) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kInvalidSessionID));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);
  ASSERT_EQ(state, ParseState::kInvalid);
}

TEST_F(TLSParserTest, ParseValidClientHello) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kValidClientHello));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);

  ASSERT_EQ(frame.content_type, tls::ContentType::kHandshake);
  ASSERT_EQ(frame.legacy_version, tls::LegacyVersion::kTLS1_0);
  ASSERT_EQ(frame.length, 282);

  ASSERT_EQ(frame.handshake_type, tls::HandshakeType::kClientHello);
  ASSERT_EQ(frame.handshake_length, 278);
  ASSERT_EQ(frame.handshake_version, tls::LegacyVersion::kTLS1_2);
  ASSERT_GT(frame.session_id.size(), 0);

  // Validate the SNI extension was parsed properly
  ASSERT_EQ(frame.body, R"({"extensions":{"server_name":["argocd-cluster-repo-server"]}})");
  ASSERT_EQ(state, ParseState::kSuccess);
}

TEST_F(TLSParserTest, ParseValidServerHello) {
  auto frame_view = CreateStringView<char>(CharArrayStringView<uint8_t>(kServerHello));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);

  ASSERT_EQ(frame.content_type, tls::ContentType::kHandshake);
  ASSERT_EQ(frame.legacy_version, tls::LegacyVersion::kTLS1_2);
  ASSERT_EQ(frame.length, 122);

  ASSERT_EQ(frame.handshake_type, tls::HandshakeType::kServerHello);
  ASSERT_EQ(frame.handshake_length, 118);
  ASSERT_EQ(frame.handshake_version, tls::LegacyVersion::kTLS1_2);
  ASSERT_GT(frame.session_id.size(), 0);
  ASSERT_EQ(state, ParseState::kSuccess);
}

TEST_F(TLSParserTest, ServerHelloExtsWithZeroLenExtension) {
  auto frame_view =
      CreateStringView<char>(CharArrayStringView<uint8_t>(kServerHelloWithZeroLengthExtension));

  tls::Frame frame;
  ParseState state = ParseFrame(message_type_t::kRequest, &frame_view, &frame);

  ASSERT_EQ(frame.content_type, tls::ContentType::kHandshake);

  ASSERT_EQ(frame.handshake_type, tls::HandshakeType::kServerHello);
  ASSERT_EQ(state, ParseState::kSuccess);
}

}  // namespace protocols
}  // namespace stirling
}  // namespace px
